package miage.rest;

import miage.rest.db.Database;
import miage.rest.resource.mail.MailClientResourceFactory;
import miage.rest.routing.RouterFactory;
import miage.rest.routing.UriTemplateFinder;
import miage.rest.security.SimpleVerifier;
import org.apache.commons.dbcp.BasicDataSource;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.PicoContainer;
import org.restlet.Component;
import org.restlet.data.Protocol;

import static org.picocontainer.Characteristics.CACHE;

/**
 * Composant serveur HTTP de base.
 * Cette classe permet de configurer et lancer le service web
 * 
 * @author Schwartz Michaël
 */
public class Server extends Component {
    /**
     * Component : Classe de base de Restlet pour créer des serveurs
     */

	/**
	 * Conteneur d'injection de dépendances
	 */
	private PicoContainer container;

	/**
	 * Configuration de ce serveur
	 */
	private Configuration config;

	/**
	 * Couche d'accès à la base de donnée
	 */
	private Database database;


	/**
	 * Fabrique de mail
	 */
	private MailClientResourceFactory mailClientResourceFactory;


	/**
	 * Création d'un serveur avec une configuration vide
	 */
	public Server() {
		config = new Configuration();
	}



	/**
	 * Initialisation d'un nouveau serveur à partir d'une configuration donnée
	 * @param configuration
	 */
	public void setConfiguration(Configuration configuration) {
		this.config = configuration;
	}

	/**
	 * Initialisation du framework Restlet
	 *	- Création d'un serveur HTTP
	 *	- Ajout de l'application
	 */
	protected void initRestlet() {

		getServers().add(Protocol.HTTP, this.config.getListenPort());
		getClients().add(Protocol.SMTP);
		
		getDefaultHost().attachDefault(container.getComponent(Application.class));


		
	}

	/**
	 * Initialisation du conteneur d'injection de dépendances
	 */
	protected void initContainer() {

		MutablePicoContainer defaultContainer = new DefaultPicoContainer();

		defaultContainer.as(CACHE).addComponent(new SimpleVerifier(config.getAdminPassword()));
		defaultContainer.as(CACHE).addComponent(mailClientResourceFactory);
		defaultContainer.as(CACHE).addComponent(database);
		defaultContainer.as(CACHE).addComponent(Application.class);
		defaultContainer.as(CACHE).addAdapter(new RouterFactory());
		defaultContainer.as(CACHE).addComponent(UriTemplateFinder.class);
		
		container = defaultContainer;
	}

	/**
	 * Initialisation de la couche d'accès à la base de donnée
	 */
	protected void initDatabase() {
			
		BasicDataSource ds = new BasicDataSource();
		
		ds.setDriverClassName(this.config.getDbDriverClassName());
		ds.setUrl(this.config.getDbUrl());
		ds.setUsername(this.config.getDbUser());
		ds.setPassword(this.config.getDbPassword());

		database = new Database(ds);
	}


	/**
	 * Initialisation de la couche de fabrique pour l'envoi de mails
	 */
	private void initMailFactory() {

		mailClientResourceFactory = new MailClientResourceFactory(	config.getMailSmtpHost(),
																	config.getMailSmtpPort(),
																	config.getMailSmtpUser(),
																	config.getMailSmtpPassword());
	}

	/**
	 * Méthode appelée avant le démarrage de l'application
	 * 
	 */
	protected void beforeStart() {
		
	}

	@Override
	public synchronized void start() throws Exception {
		if (isStopped()) {

			this.beforeStart();
			
			this.initDatabase();
			this.initMailFactory();
			this.initContainer();
			this.initRestlet();

			super.start();
		}
	}

	@Override
	public synchronized void stop() throws Exception {

		this.database = null;
		this.container = null;
		this.mailClientResourceFactory = null;
		
		super.stop();
	}


	
	/**
	 * Point d'entrée du service web.
	 * Création d'une instance de Server et lancement de celui-ci
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {

		Configuration config = new Configuration();

		config.setDbDriverClassName("com.mysql.jdbc.Driver");
		config.setDbUser("root");
		config.setDbPassword("");
		config.setDbUrl("jdbc:mysql://localhost/miage");
		config.setAdminPassword("miage");

		Server app = new Server();
		app.setConfiguration(config);
		app.start();
		
	}


}
